/*
 * C5.4.6.c
 *
 *  Created on: 2013/01/09
 *      Author: Administrator
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rule_info.h"
#include "core.h"
#include "trace.h"
#include "TraceAst.h"

static const PSZ RuleID = "C5.4.6";

//TODO
static const PSZ MESSAGE_ENG = "";
static const PSZ MESSAGE_JPN = "到達しないコード";
static const PSZ MESSAGE_CHS = "";

static const U2 RANK = MSG_RANK_ERR;

static PRULEOUT pRuleHead;
static PRULEOUT pRuleTail;

static INT RuleCheck(U2 kind, AST index, U4 event, AST* pCodeScp);
static INT StatementCheck(U2 kind, AST index, U4 event, AST* pCodeScp);
static INT DeclarationCheck(U2 kind, AST index, U4 event, AST* pCodeScp);

/******************************************************************
 * main logic
 *******************************************************************/
static S4 RuleMain(U2 kind, AST index, U4 event) {
	INT result = RULE_RESULT_OK;
	PRULEOUT newNode = NULL;
	PRULEOUT tmpNode = NULL;
	PRULEOUT tmpNode1 = NULL;

	AST codeScp = 0;

	//TODO
	result = RuleCheck(kind, index, event, &codeScp);

	if (result == RULE_RESULT_OK) {
		return EXIT_SUCCESS;
	}

	/*re-checked?*/
	tmpNode = pRuleHead;
	while (tmpNode != NULL ) {
		if (tmpNode->indexInfo == index) {
			if (result > RULE_RESULT_OK) {
				result = RULE_RESULT_OK;
			} else {
				if (tmpNode == pRuleHead) {
					pRuleHead = pRuleHead->next;
					free(tmpNode);
				} else if (tmpNode == pRuleTail) {
					tmpNode1->next = NULL;
					pRuleTail = tmpNode1;
					free(tmpNode);
				} else {
					tmpNode1->next = tmpNode->next;
					free(tmpNode);
				}
			}
			break;
		}
		tmpNode1 = tmpNode;
		tmpNode = tmpNode->next;
	}

	/*make result struct*/
	if (result > RULE_RESULT_OK) {
		newNode = (PRULEOUT) malloc(sizeof(RULEOUT));
		if (pRuleHead == NULL ) {
			pRuleHead = newNode;
		}

		//TODO
		//codeScp = ??;
		newNode->indexInfo = index;
		newNode->fileIndex = CCodeScope.getFileIndex(codeScp);
		newNode->beginLine = CCodeScope.getBeginLine(codeScp);
		newNode->beginCol = CCodeScope.getBeginLineOffset(codeScp);
		newNode->endLine = CCodeScope.getEndLine(codeScp);
		newNode->endCol = CCodeScope.getEndLineOffset(codeScp);
		newNode->ruleID = RuleID;
		newNode->errRank = RANK;

		//TODO
		sprintf(newNode->msgBuf_eng, MESSAGE_ENG);
		sprintf(newNode->msgBuf_chs, MESSAGE_CHS);
		sprintf(newNode->msgBuf_jpn, MESSAGE_JPN);

		newNode->rfileIndex = 0;
		newNode->rlocLine = 0;
		newNode->next = NULL;

		if (pRuleTail != NULL ) {
			pRuleTail->next = newNode;
		}

		pRuleTail = newNode;
	}

	return EXIT_SUCCESS;
}

VOID C5_4_6_register(VOID) {
	PRULEMAN * pCurRule = &stRuleManager;
	PRULEMAN newRuleMan = (PRULEMAN) malloc(sizeof(RULEMAN));
	memset(newRuleMan, 0, sizeof(RULEMAN));
	newRuleMan->ruleID = RuleID;
	newRuleMan->ruleSwitch = OFF;
	newRuleMan->headOut = &pRuleHead;
	newRuleMan->tailOut = &pRuleTail;
	newRuleMan->ruleMain_ast = RuleMain;
	if (stRuleManager == NULL ) {
		stRuleManager = newRuleMan;
	} else {
		while ((*pCurRule)->nextRule != NULL ) {
			pCurRule = &((*pCurRule)->nextRule);
		}
		(*pCurRule)->nextRule = newRuleMan;
	}
}

static INT RuleCheck(U2 kind, AST index, U4 event, AST* pCodeScp) {
	INT result = RULE_RESULT_OK;

	if ((kind == TR_KIND_STATEMENT) && (event & EVT_STATEMENT)) {
		result = StatementCheck(kind, index, event, pCodeScp);
	} else if ((kind == TR_KIND_DECLARATION) && (event & EVT_DECLARATION)) {
		result = DeclarationCheck(kind,index,event, pCodeScp);
	} else {
		return EXIT_SUCCESS;
	}

	return result;
}

static INT StatementCheck(U2 kind, AST index, U4 event, AST* pCodeScp) {
	INT result = RULE_RESULT_OK;

	AST astIfCondExp;
	AST astValueInfo;
	AST astStat;
	//AST astWhileCondExp;

	if (kind != TR_KIND_STATEMENT) {
		return EXIT_SUCCESS;
	}

	if (!(event & EVT_STATEMENT)) {
		return EXIT_SUCCESS;
	}

	if (CStatement.isIf(index)) {
		astIfCondExp = CStatement.if_getCondExp(index);
		if (CExpression.isConstantExp(astIfCondExp)) {
			//if the condExp is constant
			astValueInfo = CExpression.getCalcuteValue(astIfCondExp);
			if (!CValueInfo.isFloating(astValueInfo)
					&& !CValueInfo.getIntegerValue(astValueInfo).u8Remainder) {
				astStat = CStatement.if_getBody(index);
			} else {
				astStat = CStatement.if_getElseBody(index);
			}
			//if there is code in if's body or elsebody , return NG
			if (astStat != 0) {
				if (CStatement.isBlock(astStat)) {
					astStat = CStatement.block_getChain(astStat);
					if (astStat != 0) {
						*pCodeScp = CStatement.getCodeScope(astStat);
						return RULE_RESULT_NG;
					}
				} else {
					*pCodeScp = CStatement.getCodeScope(astStat);
					return RULE_RESULT_NG;
				}
			}
		}else{
			//TODO
		}
	} else if (CStatement.isSwitch(index)) {
		astStat = CStatement.switch_getBody(index);
		// get the fisrt statement from body
		if (CStatement.isBlock(astStat)) {
			astStat = CStatement.block_getChain(astStat);
		}
		// if the fisrt statement is not a case or default return NG
		if (!CStatement.isCase(astStat) && !CStatement.isDefault(astStat)) {
			*pCodeScp = CStatement.getCodeScope(astStat);
			return RULE_RESULT_NG;
		}
	} else if (CStatement.isReturn(index)) {
		astStat = CStatement.getNextStmt(index);
		if (astStat != 0) {
			*pCodeScp = CStatement.getCodeScope(astStat);
			return RULE_RESULT_NG;
		}
	} else if (CStatement.isBreak(index)) {
		astStat = CStatement.getNextStmt(index);
		if (astStat != 0) {
			*pCodeScp = CStatement.getCodeScope(astStat);
			return RULE_RESULT_NG;
		}
	}
//	else if (CStatement.isWhile(index)) {
//		// if this is a no end while
//		astWhileCondExp = CStatement.while_getCondExp(index);
//		if (CExpression.isConstantExp(astWhileCondExp)) {
//			astValueInfo = CExpression.getCalcuteValue(astWhileCondExp);
//			if (CValueInfo.isFloating(astValueInfo)
//					|| CValueInfo.getIntegerValue(astValueInfo).u8Remainder) {
//				astStat = CStatement.getNextStmt(index);
//				if (astStat != 0) {
//					*pCodeScp = CStatement.getCodeScope(astStat);
//					return RULE_RESULT_NG;
//				}
//			}
//		}else{
//
//		}
//	}
	else {
		return EXIT_SUCCESS;
	}

	return result;

}

static INT DeclarationCheck(U2 kind, AST index, U4 event, AST* pCodeScp) {
	INT result = RULE_RESULT_OK;

	if (kind != TR_KIND_DECLARATION) {
		return EXIT_SUCCESS;
	}

	if (!(event & EVT_DECLARATION)) {
		return EXIT_SUCCESS;
	}

	//TODO Function Call

	return result;
}
